﻿using FD.Tools.CopyAssist.Models;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace FD.Tools.CopyAssist.Manager
{
    /**
     * Created By: Jackie Lee(天宇遊龍)
     * CreatedOn: 2018-02-06
     */
    /// <summary>
    /// 帮助
    /// </summary>
    public class FDHelper
    {
        private static FDHelper _instance = new FDHelper();
        private readonly string configName = "config.json";
        private Config _config;

        private FDHelper()
        {
            Load();

            //    ThrowIf(() => _sourceDir.IsNullOrEmpty(), "更新文件目录，不能为空，请配置");
            //    ThrowIf(() => targetPath.IsNullOrEmpty(), "打包器目录，不能为空，请配置");
            //    ThrowIf(() => _processName.IsNullOrEmpty(), "打包器进程名称，不能为空，请配置");
            //    ThrowIf(() => !_sourceDir.IsDirExists(), "更新文件目录不存在，请配置");
            //    _targetPath = targetPath.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
            //    ThrowIf(() => _targetPath.Length == 0, "打包器目录不能为空，请配置");
            //foreach (var dir in _targetPath)
            //{
            //    ThrowIf(() => !dir.IsDirExists(), $"打包器目录{dir}不存在，请配置");
            //}

        }

        public static FDHelper Current
        {
            get
            {
                return _instance;
            }
        }

        public Config Config
        {
            get { return _config; }
        }

        /// <summary>
        /// 加载
        /// </summary>
        private void Load()
        {
            if (!File.Exists(configName))
            {
                _config = Config.Default();
                return;
            }
            var content = File.ReadAllText(configName, Encoding.UTF8);
            _config = content.FromJson<Config>();
        }

        /// <summary>
        /// 检测输入
        /// </summary>
        /// <param name="config"></param>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <param name="showCopying">显示复制过程</param>
        public void CheckValue(Config config, string source, string target, bool showCopying)
        {
            ThrowIf(() => !source.IsDirExists(), "源目录不存在");
            config.SourcePath = source;
            config.TargetPath = target;
            config.ShowCopying = showCopying;
            _config = config;
        }

        private int _count;
        private Stopwatch _stopwatch = new Stopwatch();
        /// <summary>
        /// 复制
        /// </summary>
        public void Copy()
        {
            var files = Directory.GetFiles(_config.SourcePath);
            var targetStarts = new List<string>();

            Info("Begin copying ...");
            _count = 0;
            _stopwatch.Start();
            SubCopy(_config.SourcePath, new string[] { _config.TargetPath });

            Info($"End. All the files ({_count}) was copied.used {_stopwatch.ElapsedMilliseconds}ms");
            _stopwatch.Stop();
        }

        /// <summary>
        /// 子目录操作
        /// </summary>
        /// <param name="sourcePath"></param>
        /// <param name="targetPath"></param>
        private void SubCopy(string sourcePath, string[] targetPath)
        {
            if (IgnorePath(sourcePath))
                return;
            var files = Directory.GetFiles(sourcePath);
            foreach (var path in targetPath)
            {
                if (_config.ShowCopying)
                    Info($"Begin Copying to \"{path}\" ");
                foreach (var file in files)
                {
                    if (IgnoreFile(file))
                        continue;
                    var fileName = Path.GetFileName(file);
                    CheckDir(path);
                    var targetFile = Path.Combine(path, fileName);
                    CheckFile(targetFile);
                    File.Copy(file, targetFile, true);
                    _count++;
                    if (_config.ShowCopying)
                        Info($" Copying the {fileName}", false);
                }
                if (_config.ShowCopying)
                {
                    Info($"End Copy to \"{path}\" ");
                    Info("====================================", false);
                }
            }
            var dirs = Directory.GetDirectories(sourcePath);
            foreach (var sPath in dirs)
            {
                SubCopy(sPath, ResolveTarget(targetPath, Path.GetFileName(sPath)));
            }
        }

        private void CheckFile(string targetFileName)
        {
            if (!File.Exists(targetFileName))
            {
                return;
            }
            var fi = new FileInfo(targetFileName);
            var attribs = fi.Attributes;
            if ((attribs & FileAttributes.ReadOnly) == FileAttributes.ReadOnly ||
                (attribs & FileAttributes.System) == FileAttributes.System ||
                (attribs & FileAttributes.Hidden) == FileAttributes.Hidden)
            {
                Info($"set attrib {targetFileName} from {attribs} to normal.");
                fi.Attributes = FileAttributes.Normal;
            }
        }

        /// <summary>
        /// 忽略的文件
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private bool IgnoreFile(string fileName)
        {
            var ext = Path.GetExtension(fileName);
            var fName = Path.GetFileName(fileName);
            return _config.IgnoreFileExts.IgnoreContains(ext) || _config.IgnoreFileNames.IgnoreContains(fName);
        }

        /// <summary>
        /// 忽略的目录
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private bool IgnorePath(string path)
        {
            var name = Path.GetFileName(path);
            return _config.IgnoreFolderNames.IgnoreContains(name);
        }

        private string[] ResolveTarget(string[] targetPath, string subName)
        {
            var res = new List<string>();
            targetPath.ToList().ForEach(p =>
            {
                res.Add(Path.Combine(p, subName));
            });
            return res.ToArray();
        }

        private void CheckDir(string path)
        {
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
        }

        private void Info(string msg, bool bPrint = true)
        {
            if (bPrint)
                Console.WriteLine(msg);
            FDLogger.Logger.Info(msg);
        }

        /// <summary>
        /// 结束进程
        /// </summary>
        //private void KillProcess()
        //{
        //    var pros = Process.GetProcesses().ToList().Where(p => p.ProcessName.Equals(Path.GetFileNameWithoutExtension(_processName), StringComparison.OrdinalIgnoreCase));
        //    foreach (var p in pros)
        //    {
        //        p.Kill();
        //        Info($"{p.ProcessName} killed.");
        //        Thread.Sleep(5000);
        //    }
        //}

        /// <summary>
        /// 抛出
        /// </summary>
        /// <param name="asert"></param>
        /// <param name="msg"></param>
        public void ThrowIf(Expression<Func<bool>> asert, string msg)
        {
            if (asert.Compile()())
            {
                throw new Exception(msg);
            }
        }
    }
}
